using System;
using System.Runtime.InteropServices;

namespace ServiceUtilities
{
    [StructLayout(LayoutKind.Sequential)]
    public struct ServiceDescription
    {
        public string lpDescription;
    }

    /// <summary>
    /// The struct for setting the service failure actions
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct ServiceFailureActions
    {
        public int dwResetPeriod;
        public string lpRebootMsg;
        public string lpCommand;
        public int cActions;
        public int lpsaActions;
    }


    
    public static class Win32
    {
        #region Misc Win32 Interop Stuff

        // Win32 function to open the service control manager
        public const int SC_MANAGER_ALL_ACCESS = 0xF003F;
        public const int SERVICE_ALL_ACCESS = 0xF01FF;
        public const int SERVICE_CONFIG_DESCRIPTION = 0x1;
        public const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2;
        public const int SERVICE_NO_CHANGE = -1;
        public const int ERROR_ACCESS_DENIED = 5;


        [DllImport("advapi32.dll")]
        public static extern
        IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, int dwDesiredAccess);

        // Win32 function to open a service instance
        [DllImport("advapi32.dll")]
        public static extern IntPtr
            OpenService(IntPtr hSCManager, string lpServiceName, int dwDesiredAccess);

        // Win32 function to lock the service database to perform write operations.
        [DllImport("advapi32.dll")]
        public static extern IntPtr
            LockServiceDatabase(IntPtr hSCManager);

        // Win32 function to change the service config for the failure actions.
        [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")]
        public static extern bool
            ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel,
                                        [MarshalAs(UnmanagedType.Struct)] ref ServiceFailureActions lpInfo);

        // Win32 function to change the service config for the service description
        [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")]
        public static extern bool
            ChangeServiceDescription(IntPtr hService, int dwInfoLevel,
                                     [MarshalAs(UnmanagedType.Struct)] ref ServiceDescription lpInfo);

        // Win32 function to close a service related handle.
        [DllImport("advapi32.dll")]
        public static extern bool
            CloseServiceHandle(IntPtr hSCObject);

        // Win32 function to unlock the service database.
        [DllImport("advapi32.dll")]
        public static extern bool
            UnlockServiceDatabase(IntPtr hSCManager);

        // The infamous GetLastError() we have all grown to love
        [DllImport("kernel32.dll")]
        public static extern int
            GetLastError();

        // Some Win32 constants I'm using in this app

        #endregion

        #region Shutdown Privilege Interop Stuff

        // Struct required to set shutdown privileges

        // This method adjusts privileges for this process which is needed when
        // specifying the reboot option for a service failure recover action.
        public const int TOKEN_ADJUST_PRIVILEGES = 32;
        public const int TOKEN_QUERY = 8;
        public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
        public const int SE_PRIVILEGE_ENABLED = 2;

        [DllImport("advapi32.dll")]
        public static extern bool
            AdjustTokenPrivileges(IntPtr TokenHandle, 
                                  bool DisableAllPrivileges,
                                  [MarshalAs(UnmanagedType.Struct)] ref TokenPrivileges NewState, 
                                  int BufferLength,
                                  IntPtr PreviousState, 
                                  ref int ReturnLength);


        // Looks up the privilege code for the privilege name
        [DllImport("advapi32.dll")]
        public static extern bool
            LookupPrivilegeValue(string lpSystemName, string lpName, ref long lpLuid);

        // Opens the security/privilege token for a process handle
        [DllImport("advapi32.dll")]
        public static extern bool
            OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

        /// <summary>
        /// Gets the current process handle
        /// </summary>
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();

        /// <summary>
        /// Close a windows handle
        /// </summary>
        /// <param name="hndl"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        public static extern bool CloseHandle(IntPtr hndl);
        
        #endregion
    }
}